home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2007 December / PCWKCD1207B.iso / Blogowanie poza sfera / Flock 1.0 beta / flock-1.0RC3.en-US.win32.exe / flock / components / flockMetricsService.js < prev    next >
Text File  |  2007-10-18  |  20KB  |  740 lines

  1. // BEGIN FLOCK GPL
  2. //
  3. // Copyright Flock Inc. 2005-2007
  4. // http://flock.com
  5. //
  6. // This file may be used under the terms of of the
  7. // GNU General Public License Version 2 or later (the "GPL"),
  8. // http://www.gnu.org/licenses/gpl.html
  9. //
  10. // Software distributed under the License is distributed on an "AS IS" basis,
  11. // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. // for the specific language governing rights and limitations under the
  13. // License.
  14. //
  15. // END FLOCK GPL
  16.  
  17. const MS_CONTRACTID = "@flock.com/metrics-service;1";
  18. const MS_CLASSID    = Components.ID("{bc1358fa-6e36-4d0d-a401-b0b02111114c}");
  19. const MS_CLASSNAME  = "Flock Metrics Service";
  20.  
  21.  
  22. const ENABLED_BY_DEFAULT = true;
  23.  
  24. const STORE_FILENAME = "mstore.sqlite";
  25. const OLD_STORE_FILENAME = "mstore.js";
  26.  
  27. const LOGGING_URL = "http://metrics.flock.com/anonusage.php";
  28.  
  29. const PREF_FLOCK_METRICS_ENABLED = "flock.metrics.enabled";
  30.  
  31. const PREF_FLOCK_METRICS_INTERVAL = "flock.metrics.interval";
  32. const DEFAULT_METRICS_INTERVAL = 86400;
  33.  
  34. const PREF_FLOCK_FIRSTRUN_UUID = "flock.firstrun.uuid";
  35.  
  36. const PREF_GENERAL_USERAGENT_EDITION = "general.useragent.edition";
  37. const PREF_GENERAL_USERAGENT_LOCALE = "general.useragent.locale";
  38.  
  39. const PREF_DEFAULT_SEARCH_ENGINE = "browser.search.selectedEngine";
  40. const PREF_DEFAULT_ENGINE_NAME = "browser.search.defaultenginename";
  41. const PREF_BROWSER_STARTUP_HOMEPAGE = "browser.startup.homepage";
  42. const PREF_FEED_SELECTED_ACTION = "browser.feeds.handler";
  43.  
  44. const PREF_FLOCK_FIRST_RUN_BIGDATE = "flock.first_run.bigDate";
  45.  
  46. const URI_BRAND_PROPERTIES = "chrome://branding/locale/brand.properties";
  47.  
  48. const MYWORLD_URL = "about:myworld";
  49.  
  50. const HTTP_CODE_OK = 200;
  51.  
  52. const IS_AUTHENTICATED_RSC = "http://flock.com/rdf#isAuthenticated";
  53. const IS_TRANSIENT_RSC = "http://flock.com/rdf#isTransient";
  54.  
  55.  
  56. const CC = Components.classes;
  57. const CI = Components.interfaces;
  58. const CR = Components.results;
  59. const CU = Components.utils;
  60.  
  61. CU.import("resource:///modules/FlockXPCOMUtils.jsm");
  62. CU.import("resource://gre/modules/JSON.jsm");
  63. CU.import("resource:///modules/FlockCryptoHash.jsm");
  64.  
  65.  
  66. var gApp = null;
  67. var gPref = null;
  68. var gABI = null;
  69. var gOSVersion = null;
  70.  
  71.  
  72. function getObserverService() {
  73.   return CC["@mozilla.org/observer-service;1"]
  74.          .getService(CI.nsIObserverService);
  75. }
  76.  
  77. function getCharPref(aPrefName, aDefaultValue) {
  78.   if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_STRING) {
  79.     return gPref.getCharPref(aPrefName);
  80.   } else {
  81.     return aDefaultValue;
  82.   }
  83. }
  84.  
  85. function getIntPref(aPrefName, aDefaultValue) {
  86.   if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_INT) {
  87.     return gPref.getIntPref(aPrefName);
  88.   } else {
  89.     return aDefaultValue;
  90.   }
  91. }
  92.  
  93. function getBoolPref(aPrefName, aDefaultValue) {
  94.   if (gPref.getPrefType(aPrefName) == CI.nsIPrefBranch.PREF_BOOL) {
  95.     return gPref.getBoolPref(aPrefName);
  96.   } else {
  97.     return aDefaultValue;
  98.   }
  99. }
  100.  
  101. function createStatement(aDBConn, aSQL) {
  102.   var stmt = aDBConn.createStatement(aSQL);
  103.   var wrapper = CC["@mozilla.org/storage/statement-wrapper;1"]
  104.                 .createInstance(CI.mozIStorageStatementWrapper);
  105.   wrapper.initialize(stmt);
  106.   return wrapper;
  107. }
  108.  
  109.  
  110. function MetricsService() {
  111.   gApp = CC["@mozilla.org/xre/app-info;1"]
  112.          .getService(CI.nsIXULAppInfo)
  113.          .QueryInterface(CI.nsIXULRuntime);
  114.  
  115.   gPref = CC["@mozilla.org/preferences-service;1"]
  116.            .getService(CI.nsIPrefBranch2)
  117.  
  118.   try {
  119.     gABI = gApp.XPCOMABI;
  120.  
  121.     var macutils = CC["@mozilla.org/xpcom/mac-utils;1"];
  122.     if (macutils) {
  123.       if (macutils.getService(CI.nsIMacUtils).isUniversalBinary) {
  124.         gABI = "Universal-gcc3";
  125.       }
  126.     }
  127.   } catch (ex) {
  128.   }
  129.  
  130.   try {
  131.     var sysInfo = CC["@mozilla.org/system-info;1"]
  132.                   .getService(CI.nsIPropertyBag2);
  133.     gOSVersion = sysInfo.getProperty("name") + " " +
  134.                  sysInfo.getProperty("version");
  135.   } catch (ex) {
  136.   }
  137.  
  138.   var obs = getObserverService();
  139.  
  140.   obs.addObserver(this, "flock-data-ready", false);
  141.   obs.addObserver(this, "xpcom-shutdown", false);
  142.  
  143.   this.observe(null, "nsPref:changed", PREF_FLOCK_METRICS_ENABLED);
  144. }
  145.  
  146. MetricsService.prototype = new FlockXPCOMUtils.genericComponent(
  147.   MS_CLASSNAME,
  148.   MS_CLASSID,
  149.   MS_CONTRACTID,
  150.   MetricsService,
  151.   CI.nsIClassInfo.SINGLETON,
  152.   [
  153.     CI.flockIMetricsService,
  154.     CI.flockIRDFObserver,
  155.     CI.nsITimerCallback,
  156.     CI.nsIObserver
  157.   ]
  158. );
  159.  
  160. MetricsService.prototype._xpcom_categories = [
  161.   { category: "flock-startup", service: true }
  162. ];
  163.  
  164.  
  165. MetricsService.prototype._start =
  166. function MS__start() {
  167.   this._logger = CC["@flock.com/logger;1"].createInstance(CI.flockILogger);
  168.   this._logger.init("metrics");
  169.   this._logger.info("starting up...");
  170.  
  171.   this._deleteOldStore();
  172.  
  173.   this.getUserUUID();
  174.  
  175.   this._coop = CC["@flock.com/singleton;1"]
  176.                .getService(CI.flockISingleton)
  177.                .getSingleton("chrome://flock/content/common/load-faves-coop.js")
  178.                .wrappedJSObject;
  179.  
  180.   gPref.addObserver(PREF_FLOCK_METRICS_ENABLED, this, false);
  181.   this.observe(null, "nsPref:changed", PREF_FLOCK_METRICS_ENABLED);
  182.  
  183.   this._watchLoginEvents();
  184.  
  185.   this.report("Browser-Start");
  186.  
  187.   gPref.addObserver(PREF_DEFAULT_SEARCH_ENGINE, this, false);
  188.   gPref.addObserver(PREF_BROWSER_STARTUP_HOMEPAGE, this, false);
  189.   gPref.addObserver(PREF_FEED_SELECTED_ACTION, this, false);
  190.  
  191.   var tm = CC["@mozilla.org/updates/timer-manager;1"]
  192.            .getService(CI.nsIUpdateTimerManager);
  193.   var interval = getIntPref(PREF_FLOCK_METRICS_INTERVAL,
  194.                             DEFAULT_METRICS_INTERVAL);
  195.   tm.registerTimer("background-metrics-timer", this, interval);
  196. }
  197.  
  198. MetricsService.prototype._shutdown =
  199. function MS__shutdown() {
  200.   gApp = null;
  201.   gPref = null;
  202. }
  203.  
  204. MetricsService.prototype.notify =
  205. function MS_notify(aTimer) {
  206.   this._sendReport();
  207. }
  208.  
  209. MetricsService.prototype._configure =
  210. function MS__configure() {
  211.   this._enabled = getBoolPref(PREF_FLOCK_METRICS_ENABLED, ENABLED_BY_DEFAULT);
  212.  
  213.   if (this._enabled) {
  214.     this._createStore();
  215.   } else {
  216.     this._deleteStore();
  217.   }
  218. }
  219.  
  220. MetricsService.prototype._prefChanged =
  221. function MS__prefChanged(aPref) {
  222.   switch (aPref) {
  223.     case PREF_DEFAULT_SEARCH_ENGINE:
  224.       this._reportDefaultSearchEngine();
  225.       break;
  226.  
  227.     case PREF_BROWSER_STARTUP_HOMEPAGE:
  228.       this._reportMyWorldStartPage();
  229.       break;
  230.  
  231.     case PREF_FEED_SELECTED_ACTION:
  232.       this._reportFeedReader();
  233.       break;
  234.  
  235.     case PREF_FLOCK_METRICS_ENABLED:
  236.       this._configure();
  237.       break;
  238.   }
  239. }
  240.  
  241. MetricsService.prototype.observe =
  242. function MS_observe(aSubject, aTopic, aState) {
  243.   var obs = getObserverService();
  244.  
  245.   switch (aTopic) {
  246.     case "flock-data-ready":
  247.       obs.removeObserver(this, "flock-data-ready");
  248.       this._start();
  249.       break;
  250.  
  251.     case "xpcom-shutdown":
  252.       obs.removeObserver(this, "xpcom-shutdown");
  253.       this._shutdown();
  254.       break;
  255.  
  256.     case "nsPref:changed":
  257.       this._prefChanged(aState);
  258.       break;
  259.   }
  260. }
  261.  
  262. MetricsService.prototype._getProfileFile =
  263. function MS__getProfileFile(aFileName) {
  264.   var file = CC["@mozilla.org/file/directory_service;1"]
  265.              .getService(CI.nsIProperties)
  266.              .get("ProfD", CI.nsILocalFile);
  267.   file.append(aFileName);
  268.   return file;
  269. }
  270.  
  271. MetricsService.prototype._deleteOldStore =
  272. function MS__deleteOldStore() {
  273.   var oldFile = this._getProfileFile(OLD_STORE_FILENAME);
  274.  
  275.   try {
  276.     oldFile.remove(false);
  277.   } catch (ex) {
  278.   }
  279. }
  280.  
  281. MetricsService.prototype._getMetricsDBFile =
  282. function MS__getMetricsDBFile() {
  283.   return this._getProfileFile(STORE_FILENAME);
  284. }
  285.  
  286. MetricsService.prototype._createStore =
  287. function MS__createStore() {
  288.   var dbfile = this._getMetricsDBFile();
  289.  
  290.   var storageService = CC["@mozilla.org/storage/service;1"]
  291.                        .getService(CI.mozIStorageService);
  292.   this._DBConn = storageService.openDatabase(dbfile);
  293.  
  294.   var schema = "key TEXT, value TEXT, type TEXT, time NUMBER";
  295.  
  296.   var alreadyCreated = this._DBConn.tableExists("metrics");
  297.  
  298.   if (!alreadyCreated) {
  299.     try {
  300.       this._DBConn.createTable("metrics", schema);
  301.     } catch (ex) {
  302.       this._DBConn = null;
  303.       this._enabled = false;
  304.       return;
  305.     }
  306.   }
  307.  
  308.   this._insertEvent = createStatement(this._DBConn,
  309.     "INSERT INTO metrics (key, value, type, time) " +
  310.     "VALUES (:key, :value, :type, :time)");
  311.   this._getEvents = createStatement(this._DBConn,
  312.     "SELECT * FROM metrics WHERE time <= :time");
  313.   this._deleteEvents = createStatement(this._DBConn,
  314.     "DELETE FROM metrics WHERE time <= :time");
  315.  
  316.   if (!alreadyCreated) {
  317.     this._fillPrefInfo();
  318.   }
  319. }
  320.  
  321. MetricsService.prototype._deleteStore =
  322. function MS__deleteStore() {
  323.   this._DBConn = null;
  324.  
  325.   var dbfile = this._getMetricsDBFile();
  326.   try {
  327.     dbfile.remove(false);
  328.   } catch (ex) {
  329.   }
  330. }
  331.  
  332. MetricsService.prototype._expireStore =
  333. function MS__expireStore(aExpire) {
  334.   if (!aExpire) {
  335.     return;
  336.   }
  337.  
  338.   var stmt = this._deleteEvents;
  339.   stmt.reset();
  340.   stmt.params.time = aExpire;
  341.   stmt.step();
  342. }
  343.  
  344. MetricsService.prototype.getUserUUID =
  345. function MS_getUserUUID() {
  346.   var currentUUID = getCharPref(PREF_FLOCK_FIRSTRUN_UUID);
  347.  
  348.   if (!currentUUID) {
  349.     var uuidGen = CC["@mozilla.org/uuid-generator;1"]
  350.                   .createInstance(CI.nsIUUIDGenerator);
  351.     var uuid;
  352.     try {
  353.       uuid = uuidGen.generateUUID();
  354.     } catch (ex) {
  355.       // Doh, not enough randomness, we'll try again in the future
  356.       return "0";
  357.     }
  358.  
  359.     currentUUID = String(uuid).replace(/[{}]/g, "");
  360.     gPref.setCharPref(PREF_FLOCK_FIRSTRUN_UUID, currentUUID);
  361.   }
  362.  
  363.   return currentUUID;
  364. }
  365.  
  366. MetricsService.prototype._getBaseInfo =
  367. function MS__getBaseInfo() {
  368.   var sbs = CC["@mozilla.org/intl/stringbundle;1"]
  369.             .getService(CI.nsIStringBundleService);
  370.   var bundle = sbs.createBundle(URI_BRAND_PROPERTIES);
  371.   var product = bundle.GetStringFromName("brandShortName");
  372.  
  373.   var edition = getCharPref(PREF_GENERAL_USERAGENT_EDITION, "");
  374.   var uuid = this.getUserUUID();
  375.  
  376.   var locale;
  377.   try {
  378.     locale = gPref.getComplexValue(PREF_GENERAL_USERAGENT_LOCALE,
  379.                                    nsIPrefLocalizedString).data;
  380.   } catch (ex) {
  381.     locale = getCharPref(PREF_GENERAL_USERAGENT_LOCALE);
  382.   }
  383.  
  384.   var platform = gApp.OS + "_" + gABI;
  385.  
  386.   var defaultBrowser;
  387.   try {
  388.     if (CC["@mozilla.org/browser/shell-service;1"]
  389.         .getService(CI.nsIShellService)
  390.         .isDefaultBrowser(false))
  391.     {
  392.       defaultBrowser = "true";
  393.     } else {
  394.       defaultBrowser = "false";
  395.     }
  396.   } catch (ex) {
  397.     defaultBrowser = "error";
  398.   }
  399.  
  400.   var info = { "Browser-Product": product,
  401.                "Browser-Version": gApp.version,
  402.                "Browser-BuildID": gApp.appBuildID,
  403.                "Browser-Edition": edition,
  404.                "Browser-Locale": locale,
  405.                "Browser-Platform": platform,
  406.                "Browser-OSVersion": gOSVersion,
  407.                "Browser-MetricsEnabled": this._enabled,
  408.                "User-UUID": uuid,
  409.                "Browser-ClientTime": null,
  410.                "Browser-DefaultBrowser": defaultBrowser
  411.              };
  412.  
  413.   var oldFirstRun = getCharPref(PREF_FLOCK_FIRST_RUN_BIGDATE);
  414.   if (oldFirstRun) {
  415.     info["User-FirstRun"] = oldFirstRun;
  416.   }
  417.  
  418.   return info;
  419. }
  420.  
  421. MetricsService.prototype._getFriendCounts =
  422. function MS__reportFriendCounts() {
  423.   var friendCounts = [];
  424.   var catMgr = CC["@mozilla.org/categorymanager;1"]
  425.                .getService(CI.nsICategoryManager);
  426.   var svcEnum = catMgr.enumerateCategory("flockWebService");
  427.   while (svcEnum.hasMoreElements()) {
  428.     var entry = svcEnum.getNext().QueryInterface(CI.nsISupportsCString);
  429.     if (entry) {
  430.       var contractID = catMgr.getCategoryEntry("flockWebService", entry.data);
  431.       var svc = CC[contractID].getService(CI.flockIWebService);
  432.       if (svc instanceof CI.flockISocialWebService) {
  433.         var accounts = svc.getAccounts();
  434.         while (accounts.hasMoreElements()) {
  435.           var account = accounts.getNext()
  436.                         .QueryInterface(CI.flockISocialWebServiceAccount);
  437.           friendCounts.push({service: svc.shortName,
  438.                              account: FlockCryptoHash.md5(account.urn),
  439.                              count: account.getFriendCount()});
  440.         }
  441.       }
  442.     }
  443.   }
  444.   return friendCounts;
  445. }
  446.  
  447. MetricsService.prototype._fillPrefInfo =
  448. function MS__fillPrefInfo() {
  449.   this._reportDefaultSearchEngine();
  450.   this._reportMyWorldStartPage();
  451.   this._reportFeedReader();
  452. }
  453.  
  454. MetricsService.prototype._reportDefaultSearchEngine =
  455. function MS__reportDefaultSearchEngine() {
  456.   var defaultEngine;
  457.   try {
  458.     defaultEngine = gPref.getCharPref(PREF_DEFAULT_SEARCH_ENGINE);
  459.   } catch (ex) {
  460.     defaultEngine = gPref.getComplexValue(PREF_DEFAULT_ENGINE_NAME,
  461.                                           CI.nsIPrefLocalizedString).data;
  462.   }
  463.  
  464.   if (!defaultEngine)
  465.     defaultEngine = "";
  466.  
  467.   this.report("SearchBox-DefaultSearchEngine", defaultEngine);
  468. }
  469.  
  470. MetricsService.prototype._reportMyWorldStartPage =
  471. function MS__reportMyWorldStartPage() {
  472.   var startPageHasMyWorld = false;
  473.   try {
  474.     var startPage = gPref.getComplexValue(PREF_BROWSER_STARTUP_HOMEPAGE,
  475.                                           CI.nsIPrefLocalizedString).data;
  476.     var startPages = startPage.split("|");
  477.     for each (var url in startPages) {
  478.       // Trim leading/trailing whitespace from URL
  479.       url = url.replace(/(^\s+)|(\s+$)/g, "");
  480.       if (url == MYWORLD_URL) {
  481.         startPageHasMyWorld = true;
  482.         break;
  483.       }
  484.     }
  485.   } catch (ex) {
  486.   }
  487.  
  488.   this.report("Browser-MyWorldIsHomePage", startPageHasMyWorld);
  489. }
  490.  
  491. MetricsService.prototype._reportFeedReader =
  492. function MS__reportFeedReader() {
  493.   var feedReader, action = getCharPref(PREF_FEED_SELECTED_ACTION);
  494.  
  495.   switch (action) {
  496.     case "ask":
  497.       feedReader = "news";
  498.       break;
  499.  
  500.     case "bookmarks":
  501.       feedReader = "livemarks";
  502.       break;
  503.  
  504.     default:
  505.       feedReader = "other";
  506.       break;
  507.   }
  508.  
  509.   this.report("Feeds-DefaultNewsReader", feedReader);
  510. }
  511.  
  512. MetricsService.prototype._watchLoginEvents =
  513. function MS__watchLoginEvents() {
  514.   const RDFS = CC["@mozilla.org/rdf/rdf-service;1"]
  515.                .getService(CI.nsIRDFService);
  516.  
  517.   var faves = RDFS.GetDataSource("rdf:flock-favorites");
  518.   faves.QueryInterface(CI.flockIRDFObservable);
  519.  
  520.   faves.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE, null,
  521.                        RDFS.GetResource(IS_AUTHENTICATED_RSC),
  522.                        null, this);
  523.   faves.addArcObserver(CI.flockIRDFObserver.TYPE_CHANGE, null,
  524.                        RDFS.GetResource(IS_TRANSIENT_RSC),
  525.                        null, this);
  526. }
  527.  
  528. MetricsService.prototype.rdfChanged =
  529. function MS_rdfChanged(aDS, aType, aSource, aPredicate, aTarget, aOldTarget) {
  530.   if (aTarget instanceof CI.nsIRDFLiteral) {
  531.     var account = this._coop.get_from_resource(aSource);
  532.  
  533.     if (aPredicate.ValueUTF8 == IS_AUTHENTICATED_RSC) {
  534.       if (account.isAuthenticated) {
  535.         this.report("Account-Login", account.serviceId);
  536.       } else {
  537.         this.report("Account-Logout", account.serviceId);
  538.       }
  539.     } else if (aPredicate.ValueUTF8 == IS_TRANSIENT_RSC) {
  540.       if (!account.isTransient) {
  541.         // The isTransient flag has changed.  Please note that this will
  542.         // only ever change from "true" to "false"; when the user opts to
  543.         // "keep" the service.  This means that we have to detect that the
  544.         // user opted to "FORGET" The service we have to detect is elsewher
  545.         // (as the whole account is deleted and the onChange event never
  546.         // fires).
  547.         this.report("Account-Keep", account.serviceId);
  548.       }
  549.     }
  550.   }
  551. }
  552.  
  553. MetricsService.prototype._getValueAndTypeForStorage =
  554. function MS__getValueAndTypeForStorage(aValue) {
  555.   var value, type = typeof(aValue);
  556.  
  557.   switch (type) {
  558.     case "undefined":
  559.       value = null;
  560.       break;
  561.  
  562.     case "string":
  563.       value = aValue;
  564.       break;
  565.  
  566.     case "boolean":
  567.     case "number":
  568.       value = aValue.toString();
  569.       break;
  570.  
  571.     case "object":
  572.       if (aValue) {
  573.         var realValue;
  574.  
  575.         // Pull a single object out of a 1-element array
  576.         if ("length" in aValue &&
  577.             aValue.length === 1 &&
  578.             aValue[0] &&
  579.             typeof(aValue[0]) == "object")
  580.         {
  581.           realValue = aValue[0];
  582.         } else {
  583.           realValue = aValue;
  584.         }
  585.  
  586.         // Need to make sure the object is JSON-safe, so we actually
  587.         // do a full JSON convert here instead of .toSource()
  588.         // and fall through to return null value if it fails
  589.         try {
  590.           value = "(" + JSON.toString(realValue) + ")";
  591.           break;
  592.         } catch (ex) {
  593.         }
  594.       }
  595.       // fall through
  596.  
  597.     default:
  598.       value = null;
  599.       type = "undefined";
  600.       break;
  601.   }
  602.  
  603.   return [value, type];
  604. }
  605.  
  606. MetricsService.prototype.report =
  607. function MS_report(aKey, aValue) {
  608.   if (!this._enabled) {
  609.     return;
  610.   }
  611.  
  612.   try {
  613.     var [value, type] = this._getValueAndTypeForStorage(aValue);
  614.  
  615.     var stmt = this._insertEvent;
  616.     stmt.reset();
  617.     pp = stmt.params;
  618.     pp.key = aKey;
  619.     pp.value = value;
  620.     pp.type = type;
  621.     pp.time = Date.now();
  622.     stmt.step();
  623.   } catch (ex) {
  624.   }
  625. }
  626.  
  627. MetricsService.prototype.getCurrentReport =
  628. function MS_getCurrentReport() {
  629.   var [data, expire] = this._createReport();
  630.   return data;
  631. }
  632.  
  633. MetricsService.prototype.reportNow =
  634. function MS_reportNow(aKey, aValue) {
  635.   /* XXX: only here to catch any users of the old API */
  636.   this.report("old-reportNow-" + aKey, aValue);
  637. }
  638.  
  639. MetricsService.prototype.reportCount =
  640. function MS_reportCount(aKey) {
  641.   /* XXX: only here to catch any users of the old API */
  642.   this.report("old-reportCount-" + aKey, null);
  643. }
  644.  
  645. MetricsService.prototype._createReport =
  646. function MS__createReport() {
  647.   var data = [];
  648.   var baseInfo = this._getBaseInfo();
  649.   var friendCounts = this._getFriendCounts();
  650.   var now = Date.now();
  651.   var expire = 0;
  652.  
  653.   if (this._enabled) {
  654.     expire = now;
  655.  
  656.     var sandbox = new CU.Sandbox("about:blank");
  657.  
  658.     var stmt = this._getEvents;
  659.     stmt.reset();
  660.     stmt.params.time = expire;
  661.  
  662.     while (stmt.step()) {
  663.       var row = stmt.row;
  664.       var entry = { key: row.key, time: row.time };
  665.       if (row.type == "string" || row.type == "undefined") {
  666.         entry.value = row.value;
  667.       } else {
  668.         entry.value = CU.evalInSandbox(row.value, sandbox);
  669.       }
  670.       data.push(entry);
  671.     }
  672.   }
  673.  
  674.   for each (var value in friendCounts) {
  675.     var entry = {key: "Account-FriendCount", 
  676.                  value: value, 
  677.                  time: now};
  678.     data.push(entry);
  679.   }
  680.   
  681.   for (let [key, value] in Iterator(baseInfo)) {
  682.     var entry = { key: key, value: value, time: now };
  683.     data.push(entry);
  684.   }
  685.  
  686.   return [data, expire];
  687. }
  688.  
  689. MetricsService.prototype._sendReport =
  690. function MS__sendReport() {
  691.   var [data, expire] = this._createReport();
  692.  
  693.   if (gApp.appBuildID == "0000000000") {
  694.     this._logger.debug("metrics packet: " + JSON.toString(data));
  695.     this._expireStore(expire);
  696.     return;
  697.   }
  698.  
  699.   try {
  700.     var compressor = CC["@flock.com/compress-content;1"]
  701.                      .createInstance(CI.flockICompressContent);
  702.     var compressedData = compressor.compressString(JSON.toString(data));
  703.  
  704.     var xhr = CC["@mozilla.org/xmlextras/xmlhttprequest;1"]
  705.               .createInstance(CI.nsIXMLHttpRequest);
  706.  
  707.     var self = this;
  708.     xhr.onload = function MS__sendReportOnLoad(aEvent) {
  709.       self._onLoad(aEvent, expire);
  710.     };
  711.     xhr.onerror = function MS__sendReportOnError(aEvent) {
  712.       self._onError(aEvent);
  713.     };
  714.  
  715.     xhr.backgroundRequest = true;
  716.     xhr.open("POST", LOGGING_URL);
  717.     xhr.send(compressedData);
  718.   } catch (ex) {
  719.     this._onError(null);
  720.   }
  721. }
  722.  
  723. MetricsService.prototype._onLoad =
  724. function MS__onLoad(aEvent, aExpire) {
  725.   var xhr = aEvent.target;
  726.   if (xhr.status == HTTP_CODE_OK) {
  727.     this._expireStore(aExpire);
  728.   }
  729. }
  730.  
  731. MetricsService.prototype._onError =
  732. function MS__onError(aEvent) {
  733.   // Some error happened while sending, don't clear the data
  734. }
  735.  
  736. var gComponentsArray = [MetricsService];
  737.  
  738. var NSGetModule = FlockXPCOMUtils.generateNSGetModule(MS_CLASSNAME,
  739.                                                       gComponentsArray);
  740.